package com.sdjzu.wangfuying.rxjava2study.ui;

import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.TextInputEditText;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.google.gson.Gson;
import com.rx2androidnetworking.Rx2AndroidNetworking;
import com.sdjzu.wangfuying.rxjava2study.R;
import com.sdjzu.wangfuying.rxjava2study.base.BaseFragment;
import com.sdjzu.wangfuying.rxjava2study.model.DemoBean;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link HomeFragment.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link HomeFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class HomeFragment extends BaseFragment {
    @BindView(R.id.activity_main_edt_keyword)
    TextInputEditText edt_keyword = null;

    public HomeFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @return A new instance of fragment HomeFragment.
     */
    public static HomeFragment newInstance() {
        HomeFragment fragment = new HomeFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    /**
     * 最普通的观察者和被观察者的例子
     * @param view
     */
    public void normal(View view) {
        Observable.create(new ObservableOnSubscribe<String>() {

            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("Hello ");
                e.onNext("World ");
                e.onNext("!");
                e.onComplete();
                e.onNext("End ");
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e("@Normal", "onSubscribe:" + d.toString());
            }

            @Override
            public void onNext(String s) {
                Log.e("@Normal", "onNext:" + s);
            }

            @Override
            public void onError(Throwable e) {
                Log.e("@Normal", "onError:" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e("@Normal", "onComplete:");
            }
        });
    }

    /**
     * python中的zip类似，合并两个Observable为一个，个数为min(len(o1), len(o2))
     *
     * @param view
     */
    public void zip(View view) {
        Observable<Integer> o1 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
                e.onNext(4);
                e.onNext(5);
            }
        });
        Observable<Integer> o2 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(6);
                e.onNext(7);
                e.onNext(8);
                e.onNext(9);
                e.onNext(10);
                e.onNext(6);
                e.onNext(7);
                e.onNext(8);
                e.onNext(9);
                e.onNext(10);
            }
        });
        Observable.zip(o1, o2, new BiFunction<Integer, Integer, Integer>() {

            @Override
            public Integer apply(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer o) throws Exception {
                Log.e("@Zip", o.toString());
            }
        });
    }

    /**
     * 一对一映射
     * @param view
     */
    public void map(View view) {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
                e.onNext(4);
            }
        }).map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "Num:" + integer.toString();
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("@Map", s);
            }
        });
    }

    /**
     * 一个类型这换成一个Observable，进而可以对这个Observable进行点操作
     * @param view
     */
    public void flatMap(View view) {
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("ABCDE");
            }
        }).doOnNext(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("@FlatMap_doOnNext", s);
            }
        }).flatMap(new Function<String, ObservableSource<Integer>>() {
            @Override
            public ObservableSource<Integer> apply(String s) throws Exception {
                List<Integer> list = new LinkedList<>();
                for (char c : s.toCharArray()) {
                    list.add((int) c);
                }
                return Observable.fromIterable(list);
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e("@FlatMap", integer.toString());
            }
        });
    }

    /**
     * 筛选
     * @param view
     */
    public void filter(View view) {
        Observable.just(10, 20, 30, 40)
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) throws Exception {
                        return integer >= 20;
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e("@Filter", integer.toString());
            }
        });
    }

    /**
     * SQL中的limit操作
     * @param view
     */
    public void skipAndTake(View view) {
        Observable.just(10, 20, 30, 40, 50, 60)
                .skip(2)
                .take(2)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e("@SkipAndTake", integer.toString());
                    }
                });
    }

    /**
     * 定时任务，接收到的是一个代表激发时间的long时间戳
     * @param view
     */
    public void interval(View view) {
        Observable.interval(2, 5, TimeUnit.SECONDS)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Log.e("@Interval", aLong.toString());
                    }
                });
    }

    /**
     * SQL distinct
     * @param view
     */
    public void distinct(View view) {
        Observable.just(1, 1, 2, 2, 3, 3)
                .distinct()
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e("@Distinct", integer.toString());
                    }
                });
    }

    /**
     * 分组 group
     * @param view
     */
    public void buffer(View view) {
        Observable.just(1, 2, 3, 4, 5)
                .buffer(3, 3)
                .subscribe(new Consumer<List<Integer>>() {
                    @Override
                    public void accept(List<Integer> integers) throws Exception {
                        for (Integer i : integers) {
                            Log.e("@Buffer", i.toString());
                        }
                        Log.e("@Buffer", "===========");
                    }
                });
    }

    /**
     * 去抖动，忽略一定时间内的事件
     * @param view
     */
    public void debounce(View view) {
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                for (int i = 0; i < 10; i++) {
                    e.onNext(i + "");
                    Thread.sleep((long) (Math.random() * 1000));
                }
            }
        }).debounce(500, TimeUnit.MILLISECONDS)
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.e("@Debounce", s);
                    }
                });
    }

    /**
     * 默认值
     * @param view
     */
    public void last(View view) {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onComplete();
            }
        }).last(6)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e("@Last", integer.toString());
                    }
                });
    }

    /**
     * 简单的连接合并
     * @param view
     */
    public void merge(View view) {
        Observable.merge(Observable.just(1, 2, 3), Observable.just(4, 5, 6))
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer number) throws Exception {
                        Log.e("@Merge", number.toString());
                    }
                });
    }

    /**
     * 通过二元运算进行合并
     * @param view
     */
    public void reduce(View view) {
        Observable.just(1, 2, 3, 4, 5)
                .reduce(new BiFunction<Integer, Integer, Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) throws Exception {
                        Log.e("@Reduce", String.format("apply %s and %s", integer.toString(), integer2.toString()));
                        return integer + integer2;
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e("@Reduce", integer.toString());
            }
        });
    }

    /**
     * 同reduce，但输出每一步的过程
     * @param view
     */
    public void scan(View view) {
        Observable.just(1, 2, 3, 4, 5)
                .scan(new BiFunction<Integer, Integer, Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) throws Exception {
                        return integer + integer2;
                    }
                }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e("@Scan", integer.toString());
            }
        });
    }

    /**
     * 按照时间来分组，把不同时间段内的事件放在不同的Observable中
     * @param view
     */
    public void window(View view) {
        Observable.interval(1, TimeUnit.SECONDS)
                .take(15)
                .window(3, TimeUnit.SECONDS)
                .subscribe(new Consumer<Observable<Long>>() {
                    @Override
                    public void accept(Observable<Long> longObservable) throws Exception {
                        longObservable.subscribe(new Consumer<Long>() {
                            @Override
                            public void accept(Long aLong) throws Exception {
                                Log.e("@Window:" + this, aLong.toString());
                            }
                        });
                    }
                });
    }

    /**
     * 多方分发
     * @param view
     */
    public void publishSubject(View view) {
        PublishSubject<String> ps = PublishSubject.create();
        ps.subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("@PublishSubject0", s);
            }
        });
        ps.subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("@PublishSubject1", s);
            }
        });
        ps.onNext("Hello");
    }

    /**
     * 用okHttp进行请求
     * @param view
     */
    public void simpleRequest(View view) {
        Observable.create(new ObservableOnSubscribe<Response>() {
            @Override
            public void subscribe(ObservableEmitter<Response> e) throws Exception {
                Request.Builder builder = new Request.Builder().url("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                        .get();
                Request request = builder.build();
                Call call = new OkHttpClient().newCall(request);
                e.onNext(call.execute());
            }
        }).map(new Function<Response, DemoBean>() {
            @Override
            public DemoBean apply(Response response) throws Exception {
                return new Gson().fromJson(response.body().string(), DemoBean.class);
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(Schedulers.io())
                .doOnNext(new Consumer<DemoBean>() {
                    @Override
                    public void accept(DemoBean demoBean) throws Exception {
                        Log.e("@DoOnNext", demoBean.toString());
                        if (demoBean.getErrorCode() == 10005) {
                            demoBean.setErrorCode(20005);
                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<DemoBean>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(DemoBean demoBean) {
                        Log.e("@SimpleRequest", demoBean.toString());
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    /**
     * RxJava & AndroidNetworking code
     */

    /**
     * 使用AndroidNetworking库进行请求
     */
    public void androidNetworking() {
        Rx2AndroidNetworking.get("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                .build()
                .getObjectObservable(DemoBean.class)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<DemoBean>() {
                    @Override
                    public void accept(DemoBean demoBean) throws Exception {
                        Log.e("@AndroidNetworking", demoBean.toString());
                        edt_keyword.setError(demoBean.getReason());
                    }
                });
    }

    /**
     * 合并两个请求，然后才继续做一些事情
     * @param view
     */
    public void zipNetworking(View view) {
        Observable<DemoBean> o1 = Rx2AndroidNetworking.get("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                .build()
                .getObjectObservable(DemoBean.class);
        Observable<DemoBean> o2 = Rx2AndroidNetworking.get("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                .build()
                .getObjectObservable(DemoBean.class);
        Observable.zip(o1, o2, new BiFunction<DemoBean, DemoBean, String>() {
            @Override
            public String apply(DemoBean demoBean, DemoBean demoBean2) throws Exception {
                return demoBean.toString() + demoBean2.toString();
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.e("@ZipNetworking", s);
                    }
                });

    }

    /**
     * 嵌套
     * @param view
     */
    public void flatMapNetworking(View view) {
        Rx2AndroidNetworking.get("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                .build().getObjectObservable(DemoBean.class)
                .subscribeOn(Schedulers.io())
                .flatMap(new Function<DemoBean, ObservableSource<String>>() {
                    @Override
                    public ObservableSource<String> apply(final DemoBean demoBean) throws Exception {
                        return Observable.create(new ObservableOnSubscribe<String>() {
                            @Override
                            public void subscribe(ObservableEmitter<String> e) throws Exception {
                                e.onNext(demoBean.getReason());
                            }
                        });
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.e("@FlatNetworking", s);
                    }
                });
    }

    /**
     * 按顺序的执行两个任务
     * 特性：第一个onComplete之后第二个才会触发
     * 读取数据流程：我要读数据->有缓存？---是->直接读缓存
     *                          |-----否->网络请求->保存缓存数据
     * @param view
     */
    @OnClick(R.id.activity_main_btn_normal)
    public void concatNetworking(View view) {
        Observable<DemoBean> cache = Observable.create(new ObservableOnSubscribe<DemoBean>() {
            @Override
            public void subscribe(ObservableEmitter<DemoBean> e) throws Exception {
                boolean hasCache = false;
                if (hasCache) {
                    e.onNext(new DemoBean(99999, "未知错误"));
                } else {
                    e.onComplete();
                }
            }
        });

        Observable<DemoBean> network = Rx2AndroidNetworking.get("http://api.avatardata.cn/MobilePlace/LookUp?key=ec47b85086be4dc8b5d941f5abd37a4e&mobileNumber=13021671512")
                .build()
                .getObjectObservable(DemoBean.class);

        Observable.concat(cache, network)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<DemoBean>() {
                    @Override
                    public void accept(DemoBean demoBean) throws Exception {
                        Log.e("@ConcatNetworking", demoBean.toString());
                        edt_keyword.setError(demoBean.toString());
                    }
                });
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        void onFragmenInteraction(Uri uri);
    }
}
